/*
 * Render.java
 *
 * Created on 11 de Julho de 2007, 20:40
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package br.com.cpqd.ssar.gerenciador;

import br.com.cpqd.ssar.utilitarias.*;
import br.com.cpqd.ssar.utilitarias.ListaGeometrias;
import br.com.cpqd.ssar.utilitarias.Geometria;
import br.com.cpqd.ssar.utilitarias.AtributosGeometria;

import com.sun.opengl.util.BufferUtil;
import com.sun.opengl.util.GLUT;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Collection;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.util.Vector;
import demos.common.TextureReader;
import demos.common.TextureReader.Texture;
import java.io.IOException;

/**
 * Classe de Renderização de Geometrias
 * @author Igor José
 * @version 1.0
 */
public class Render implements GLEventListener, KeyListener,
        MouseListener, MouseMotionListener, MouseWheelListener {

    private boolean statusCalculaCoordenada = false;
    private final static float ROTACAO_STEP = 1.0f;
    private final static float POSICAO_STEP = 0.5f;
    //   private final static float ZOOM_STEP = 0.5f;
    private boolean statusSelecao = false;
    private float h;
    private static final int BUFSIZE = 1024;
    //   private int[] selectBuf = new int[BUFSIZE];
//    private IntBuffer selectBuffer = BufferUtil.newIntBuffer(BUFSIZE);
//    private int hits;

    /*ILUMINACAO E COR*/
    private float[] luzAmbiente = {0.2f, 0.2f, 0.2f, 1.0f};
    /* ViewPort */
    private int[] viewport = new int[4];
    private int xPos;
    private int yPos;
    /* Variaveis Globais da Cena de Renderiza��o */
    private float rotateX = 0.0f;
    private float rotateY = 0.0f;
    private float rotateZ = 0.0f;
    private float xPosition = 0.0f;
    private float yPosition = 0.0f;
    private float zPosition = -10.0f;

     private float rotateXInicial = 0.0f;
    private float rotateYInicial = 0.0f;
    private float rotateZInicial = 0.0f;
    private float xPositionInicial = 0.0f;
    private float yPositionInicial = 0.0f;
    private float zPositionInicial = -10.0f;
    
    //* Limites da rotação
    private float rotacaoXMaxima = 360.0f;
    private float rotacaoXMinima = -360.0f;
    private float rotacaoYMaxima = 360.0f;
    private float rotacaoYMinima = -360.0f;
    private float rotacaoZMaxima = 360.0f;
    private float rotacaoZMinima = -360.0f;
    //* Limites do translado
    private float posicaoXMaxima = 0.0f;
    private float posicaoXMinima = 0.0f;
    private float posicaoYMaxima = 0.0f;
    private float posicaoYMinima = 0.0f;
    private float posicaoZMaxima = 0.0f;
    private float posicaoZMinima = 0.0f;
    private boolean grid = true;
    private float xi,  yi,  zi,  xf,  zf,  yf;
    private float raio,  altura;
    private boolean confirmar = false;
    private static GL gl;
    private static final GLU glu = new GLU();
    private static final GLUT glut = new GLUT();
    private GLCanvas glCanvas;
    private int clickTijolo = 0;
    private int clickEsfera = 0;
    private int clickCilindro = 0;
    private int clickCone = 0;
    private int clickLine = 0;
    private int clickFonte = 0;
    private Geometria geo = new Geometria();
    private int idGeo = 0;
    private boolean empty = false;
    private boolean emptyFonte = false;
    private Collection<RenderListener> renderListeners = new ArrayList<RenderListener>();
    double mvmatrix[] = new double[16];
    double projmatrix[] = new double[16];
    int realy = 0;// GL y coord pos
    private float blocoX = 63; /* para zPosition -10 */

    private float blocoY = 67; /* para zPosition -10 */

    private boolean eixos = false;
    double wcoord[] = new double[4];// wx, wy, wz;// returned xyz coords
    private Vector listVectorGeometry = new Vector();
    private Vector listVectorFontes = new Vector();
    private boolean triangularizada = false;
    private float[] coordenadasFonte = new float[3];
    private int focus;
    private boolean teclado = true;
    private int clickMouse = 0;
    private int tamGradeX = 20;
    private int tamGradeY = 20;
    private int tamGradeZ = 20;
    private Color corGrid = new Color(204, 204, 204);
    private float fatorDivisaoGridX = 1.0f;
    private float fatorDivisaoGridY = 1.0f;
    private int objSelecionado;
//    private boolean solido = true;
    private float xGridInicio;
    private float xGridFim;
    private float yGridInicio;
    private float yGridFim;
//    private IntBuffer filtro;
    private int texture;

    /**
     * Retorna geometria
     * @return Geometry geo
     */
    public Geometria getGeometria() {
        return this.geo;

    }

    public Color getCorGrid() {
        return this.corGrid;
    }

//    public void setSolido(boolean status) {
//        solido = status;
//    }
    public void setCorGrid(Color cor) {
        this.corGrid = cor;
    }

    public void setDesenharGrid(boolean status) {
        this.grid = status;
    }

    public boolean isEixosEnable() {
        return this.eixos;
    }

    public void setXGridInicio(float tamanho) {
        this.xGridInicio = tamanho;
    }

    public void setYGridInicio(float tamanho) {
        this.yGridInicio = tamanho;
    }

    public void setXGridFim(float tamanho) {
        this.xGridFim = tamanho;
    }

    public void setYGridFim(float tamanho) {
        this.yGridFim = tamanho;
    }

    public void setFatorDivisaoGridX(float valor) {
        fatorDivisaoGridX = valor;
    }

    public void setFatorDivisaoGridY(float valor) {
        fatorDivisaoGridY = valor;
    }

    public int getObjSelecionado() {
        return objSelecionado;
    }

    public void setSelecao() {
        if (statusSelecao) {
            statusSelecao = false;
            statusCalculaCoordenada = true;
        } else {
            statusSelecao = true;
            statusCalculaCoordenada = false;

        }
        System.out.println("status selecao: " + statusSelecao);

    }

     public void setDesenharEixos(boolean status) {
        this.eixos = status;
        glCanvas.display();
    }

    public boolean isGridEnable() {
        return this.grid;
    }

    public int getClickMouse() {
        return this.clickMouse;
    }

    public boolean isTeclado() {
        boolean temp = teclado;
        teclado = false;
        return temp;
    }

    public int getCanvasFocus() {
        return focus;
    }

    public float[] getCoordenadasFonte() {
        return coordenadasFonte;
    }

    public void setCanvasFocus(int focus) {
        this.focus = focus;
    }

    /**
     * Seta visão para cada tipo de plano:
     * Perspectiva
     * Top (Cima)
     * Front (Frente)
     * Side (Lado)
    @params float rotateX, float rotateY, float rotateZ, float xPosition,
    float yPosition, float zPosition
     */
    public void setVisao(float rotateX, float rotateY, float rotateZ, float xPosition,
            float yPosition, float zPosition) {
        this.rotateX = rotateX;
        this.rotateY = rotateY;
        this.rotateZ = rotateZ;

        this.xPosition = xPosition;
        this.yPosition = yPosition;
        this.zPosition = zPosition;
    }

    public float[] getVisao() {
        float ret[] = new float[6];

        ret[0] = rotateX;
        ret[1] = rotateY;
        ret[2] = rotateZ;
        ret[3] = xPosition;
        ret[4] = yPosition;
        ret[5] = zPosition;

        return ret;
    }

    /**
     * Metodo que recebe a Estrutura de Arvore para renderizacao das Geometrias
     * @param Vector - list
     */
    public void setListGeometry(Vector list) {
        listVectorGeometry = list;
    }

    /**
     * Metodo que recebe a Estrutura de Arvore para renderizacao das Fontes
     * @param Vector - list
     */
    public void setListaFonte(Vector list) {
        listVectorFontes = list;
    }

    /**
     * Adiciona um novo Listener de eventos a classe Render
     * @param RenderListener l
     */
    public synchronized void addRenderListener(RenderListener l) {
        if (!renderListeners.contains(l)) {
            renderListeners.add(l);
        }
    }

    /**
     * Remove Listener de eventos da classe Render
     * @param RenderListener l
     */
    public synchronized void removeRenderListener(RenderListener l) {

        renderListeners.remove(l);
    }

    /**
     * Notifica evento "Geometria Inserida"
     */
    public void novaGeometria() {
        notificarNovaGeometria();
    }

    /**
     * Notifica evento "Fonte Inserida"
     */
    public void novaFonte() {
        notificaNovaFonte();
    }

    public void canvasFocus() {
        notificarFocusCanvas();
    }

    /**
     * Notifica geometria inserida aos Listeners previamente adicionados
     */
    private void notificarNovaGeometria() {

        Collection<RenderListener> tl;
        synchronized (this) {
            // Clonar para evitar problemas de sincronização
            // durante a propagação do evento
            tl = (Collection) (((ArrayList) renderListeners).clone());
        }
        RenderEvent evento = new RenderEvent(this);
        for (RenderListener t : tl) {
            t.geometriaInserida(evento);
        }
    }

    private void notificarFocusCanvas() {

        Collection<RenderListener> tl;
        synchronized (this) {
            // Clonar para evitar problemas de sincronização
            // durante a propagação do evento
            tl = (Collection) (((ArrayList) renderListeners).clone());
        }
        RenderEvent evento = new RenderEvent(this);
        for (RenderListener t : tl) {
            t.canvasFocus(evento);
        }
    }

    /**
     * Notifica geometria inserida aos Listeners previamente adicionados
     */
    private void notificaNovaFonte() {

        Collection<RenderListener> tl;
        synchronized (this) {
            // Clonar para evitar problemas de sincronização
            // durante a propagação do evento
            tl = (Collection) (((ArrayList) renderListeners).clone());
        }
        RenderEvent evento = new RenderEvent(this);
        for (RenderListener t : tl) {
            t.fonteInserida(evento);
        }
    }

    private void notificaObjSelecionado() {

        Collection<RenderListener> tl;
        synchronized (this) {
            // Clonar para evitar problemas de sincronização
            // durante a propagação do evento
            tl = (Collection) (((ArrayList) renderListeners).clone());
        }
        RenderEvent evento = new RenderEvent(this);
        for (RenderListener t : tl) {
            t.objSelecionado(evento);
        }
    }

    /**
     * Verifica se o nó que contém as listas de geometrias está vazio
     * @return boolean
     */
    private boolean iListGeometryEmpty() {

        if (listVectorGeometry.size() == 0) {
            empty = true;
        } else {
            empty = false;
        }
        return empty;
    }

    /**
     * Verifica se o nó que contém as listas de geometrias está vazio
     * @return boolean
     */
    private boolean iListFonteEmpty() {

        if (listVectorFontes.size() == 0) {
            emptyFonte = true;
        } else {
            emptyFonte = false;
        }
        return emptyFonte;
    }

    /**
     * Habilita a construção do objeto Line (Linha)
     * @param int clickLine
     */
    public void setClickLine(int clickLine) {
        this.clickLine = clickLine;
    }

    /**
     * Habilita a construção do objeto Fonte 
     * @param int clickFonte
     */
    public void setClickFonte(int clickFonte) {
        this.clickFonte = clickFonte;
    }

    /**
     * Habilita a construção do objeto Cone 
     * @param int clickConoe
     */
    public void setClickCone(int clickCone) {
        this.clickCone = clickCone;
    }

    /**
     * Habilita a construção do objeto Cilindro 
     * @param int clickCilindro
     */
    public void setClickCilindro(int clickCilindro) {
        this.clickCilindro = clickCilindro;
    }

    /**
     * Habilita a construção do objeto Brick (Tijolo) 
     * @param int clickTijolo
     */
    public void setClickBrick(int clickTijolo) {
        this.clickTijolo = clickTijolo;
    }

    /**
     * Habilita a construção do objeto Esfera (Esfera) 
     * @param int clickEsfera
     */
    public void setClickEsfera(int clickEsfera) {
        this.clickEsfera = clickEsfera;
    }

    /**
     * Confirma a inserção de nova geometria
     * @return boolean confirmar
     */
    public boolean isConfirmar() {
        return confirmar;
    }

    /**
     * Seta atributo "confirmar"
     * @param boolean confirmar
     */
    public void setConfirmar(boolean confirmar) {
        this.confirmar = confirmar;
    }

    /**
     * Recebe e atualiza o atributo GLCanvas
     * @param int clickConoe
     */
    public void setGLCanvas(GLCanvas canvas) {
        glCanvas = canvas;

    }

    public void rotacaoLimite(float rotacaoXMinima, float rotacaoXMaxima,
            float rotacaoYMinima, float rotacaoYMaxima,
            float rotacaoZMinima, float rotacaoZMaxima) {
        this.rotacaoXMinima = rotacaoXMinima;
        this.rotacaoXMaxima = rotacaoXMaxima;
        this.rotacaoYMinima = rotacaoYMinima;
        this.rotacaoYMaxima = rotacaoYMaxima;
        this.rotacaoZMinima = rotacaoZMinima;
        this.rotacaoZMaxima = rotacaoZMaxima;
    }

    public void posicaoLimite(float posicaoXMinima, float posicaoXMaxima,
            float posicaoYMinima, float posicaoYMaxima,
            float posicaoZMinima, float posicaoZMaxima) {
        this.posicaoXMinima = posicaoXMinima;
        this.posicaoXMaxima = posicaoXMaxima;
        this.posicaoYMinima = posicaoYMinima;
        this.posicaoYMaxima = posicaoYMaxima;
        this.posicaoZMinima = posicaoZMinima;
        this.posicaoZMaxima = posicaoZMaxima;
    }

    /**
     * Rotaciona o eixo X em uma unidade positiva
     */
    public void addRotateX() {
        if (rotacaoXMaxima == 360 || rotateX < rotacaoXMaxima) {
            rotateX += ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Rotaciona o eixo Y em uma unidade positiva
     */
    public void addRotateY() {
        if (rotacaoYMaxima == 360 || rotateY < rotacaoYMaxima) {
            rotateY += ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Rotaciona o eixo Z em uma unidade positiva
     */
    public void addRotateZ() {
        if (rotacaoZMaxima == 360 || rotateZ < rotacaoZMaxima) {
            rotateZ += ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Rotaciona o eixo X em uma unidade negativa
     */
    public void subRotateX() {
        if (rotacaoXMinima == -360 || rotateX > rotacaoXMinima) {
            rotateX -= ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Rotaciona o eixo Y em uma unidade negativa
     */
    public void subRotateY() {
        if (rotacaoYMinima == -360 || rotateY > rotacaoYMinima) {
            rotateY -= ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Rotaciona o eixo Z em uma unidade negativa
     */
    public void subRotateZ() {
        if (rotacaoZMinima == -360 || rotateZ > rotacaoZMinima) {
            rotateZ -= ROTACAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo Z em uma unidade positiva
     */
    public void addZPosition() {
        if (posicaoZMaxima == 0 || zPosition < posicaoZMaxima) {
            zPosition += POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo Z em uma unidade negativa
     */
    public void subZPosition() {
        if (posicaoZMinima == 0 || zPosition > posicaoZMinima) {
            zPosition -= POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo Y em uma unidade negativa
     */
    public void subYPosition() {
        if (posicaoYMinima == 0 || yPosition > posicaoYMinima) {
            yPosition -= POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo Y em uma unidade positiva
     */
    public void addYPosition() {
        if (posicaoYMaxima == 0 || yPosition < posicaoYMaxima) {
            yPosition += POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo X em uma unidade positiva
     */
    public void addXPosition() {
        if (posicaoXMaxima == 0 || xPosition < posicaoXMaxima) {
            xPosition += POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Translada o eixo X em uma unidade negativa
     */
    public void subXPosition() {
        if (posicaoXMinima == 0 || xPosition > posicaoXMinima) {
            xPosition -= POSICAO_STEP;
            glCanvas.display();
        }
    }

    /**
     * Gera o Grid no GLCanvas
     */
    public void drawGrid(GLAutoDrawable GLDrawable) {
        gl = GLDrawable.getGL();
        // Function that draws the gridlines and x,y,z axis
        if (grid) {

            gl.glColor3f(corGrid.getRed() / 255, corGrid.getGreen() / 255, corGrid.getBlue() / 255);
            gl.glLineWidth(1.0f);

            float x = xGridInicio;
            int qtdCelulasX = (int) ((xGridFim - xGridInicio) / fatorDivisaoGridX);
            int qtdCelulasY = (int) ((yGridFim - yGridInicio) / fatorDivisaoGridY);

            int z = 0;
            /* LINHAS VERTICAIS DO GRID */
            gl.glBegin(GL.GL_LINES);
            for (int i = 0; i <= qtdCelulasX; i++) {
                gl.glVertex3f(x, yGridInicio, z);
                gl.glVertex3f(x, yGridFim, z);
                x += fatorDivisaoGridX;

            }
            gl.glEnd();

            float y = yGridInicio;
            // System.out.println("y: " + y);
            /* LINHAS HORIZONTAIS DO GRID */
            gl.glBegin(GL.GL_LINES);
            for (int i = 0; i <= qtdCelulasY; i++) {
                gl.glVertex3f(xGridInicio, y, z);
                gl.glVertex3f(xGridFim, y, z);
                y += fatorDivisaoGridY;
            }
            gl.glEnd();
        }

//        gl.glColor3f(255.0f, 0.0f, 0.0f);
//        gl.glLineWidth(3.0f);
//        gl.glBegin(GL.GL_LINES);
//        gl.glVertex3f(0, 0, 0);
//        gl.glVertex3f(5, 0, 0);
//        gl.glEnd();
//        gl.glRasterPos3f(4.5f, 0.5f, 0.5f);
//        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'X');
//
//        gl.glColor3f(0.0f, 255.0f, 0.0f);
//        gl.glBegin(GL.GL_LINES);
//        gl.glVertex3f(0, 0, 0);
//        gl.glVertex3f(0, 5, 0);
//        gl.glEnd();
//        gl.glRasterPos3f(0.5f, 4.5f, 0.5f);
//        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Y');
//
//        gl.glColor3f(0.0f, 0.0f, 255.0f);
//        gl.glBegin(GL.GL_LINES);
//        gl.glVertex3f(0, 0, 0);
//        gl.glVertex3f(0, 0, 5);
//        gl.glEnd();
//        gl.glRasterPos3f(0.5f, 0.5f, 4.5f);
//        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Z');
    }

     private void drawEixos(GLAutoDrawable GLDrawable){
        gl = GLDrawable.getGL();

        //Centro do eixo
        gl.glColor3f(1.0f, 0.0f, 0.0f);
        gl.glPushMatrix();
        gl.glTranslatef(0, 0, 0);
        glut.glutSolidSphere(0.5, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();

        //Eixo X
        gl.glPushMatrix();
        gl.glTranslatef(0, 0, 0);
        gl.glRotatef(90, 0.0f, 1.0f, 0.0f);
        glut.glutSolidCylinder(0.2f, 2.5, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Seta eixo X
        gl.glPushMatrix();
        gl.glTranslatef(2.5f, 0, 0);
        gl.glRotatef(90, 0.0f, 1.0f, 0.0f);
        glut.glutSolidCone(0.5f, 1, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Letra X
        gl.glRasterPos3f(4f, 0.0f, -0.0f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'X');

        //Eixo Y
        gl.glColor3f(0.0f, 1.0f, 0.0f);
        gl.glPushMatrix();
        gl.glTranslatef(0, 0, 0);
        gl.glRotatef(-90, 1.0f, 0.0f, 0.0f);
        glut.glutSolidCylinder(0.2f, 2.5, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Seta eixo Y
        gl.glPushMatrix();
        gl.glTranslatef(0, 2.5f, 0);
        gl.glRotatef(-90, 1.0f, 0.0f, 0.0f);
        glut.glutSolidCone(0.5f, 1, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Letra Y
        gl.glRasterPos3f(0.0f, 4f, -0.0f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Y');

        //Eixo Z
        gl.glColor3f(0.0f, 0.0f, 1.0f);
        gl.glPushMatrix();
        gl.glTranslatef(0, 0, 0);
        glut.glutSolidCylinder(0.2f, 2.5, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Seta eixo Y
        gl.glPushMatrix();
        gl.glTranslatef(0, 0, 2.5f);
        glut.glutSolidCone(0.5f, 1, 15, 15);
        gl.glPopMatrix();
        gl.glFlush();
        //Letra Z
        gl.glRasterPos3f(-0.0f, 0.0f, 4f);
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_10, 'Z');
    }

    /**
     * Renderiza a Árvore de Geometrias
     */
    void renderTreeGeometrias() {

        ListaGeometrias listGeo;

        /* for para o objeto 'nodeTree' que contem os grupos de objetos
         * e cada grupo de objeto contem uma lista de objetos do tipo Geometry
         */

        for (int i = 0; i < listVectorGeometry.size(); i++) {

            listGeo = (ListaGeometrias) listVectorGeometry.get(i);

            /* for para percorrer os objetos dentro do grupo */
            for (int j = 0; j < listGeo.getGeo().size(); j++) {

                Geometria g = new Geometria();
                /* recebendo o obj Geometry */
                g = (Geometria) listGeo.getGeo().get(j);
                /* recebendo o tipo de geometria */
                AtributosGeometria gAtt = g.getAtributos();

                if (statusSelecao) {
                    //  System.out.println("render tree geometrias");
                    gl.glLoadName(g.getIdentificador());

                }

                if (gAtt instanceof Cilindro) {
                    drawCylinder(g, listGeo);
                }

                if (gAtt instanceof Cone) {
                    drawCone(g, listGeo);
                }

                if (gAtt instanceof Tijolo) {
                    drawBrick(g, listGeo);
                }

                if (gAtt instanceof Esfera) {
                    drawSphere(g, listGeo);
                }

                if (gAtt instanceof STL) {
                    drawSTL(g, listGeo);
                }
            }
        }
    }

    /**
     * Renderiza as Fontes existentes
     */
    void renderTreeFontes() {

        FonteEletromagneticaSimulacao fonte;

        for (int i = 0; i < listVectorFontes.size(); i++) {

            fonte = new FonteEletromagneticaSimulacao();
            fonte = (FonteEletromagneticaSimulacao) listVectorFontes.get(i);

            gl.glPushMatrix();
            gl.glTranslatef((float) fonte.getX(), (float) fonte.getY(), (float) fonte.getZ());
            gl.glColor3f((float) fonte.getCor().getRed() / 255,
                    (float) fonte.getCor().getGreen() / 255,
                    (float) fonte.getCor().getBlue() / 255);

            gl.glBindTexture(GL.GL_TEXTURE_2D, texture);

            gl.glBegin(GL.GL_QUADS);
            // Front Face
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(-0.5f, -0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(0.5f, -0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(0.5f, 0.5f, 0.5f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(-0.5f, 0.5f, 0.5f);
            // Back Face
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(-0.5f, -0.5f, -0.5f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(-0.5f, 0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(0.5f, 0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(0.5f, -0.5f, -0.5f);
            // Top Face
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(-0.5f, 0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(-0.5f, 0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(0.5f, 0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(0.5f, 0.5f, -0.5f);
            // Bottom Face
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(-0.5f, -0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(0.5f, -0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(0.5f, -0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(-0.5f, -0.5f, 0.5f);
            // Right face
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(0.5f, -0.5f, -0.5f);
            gl.glTexCoord2f(1.0f, 0.5f);
            gl.glVertex3f(0.5f, 0.5f, -0.5f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(0.5f, 0.5f, 0.5f);
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(0.5f, -0.5f, 0.5f);
            // Left Face
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(-0.5f, -0.5f, -0.5f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(-0.5f, -0.5f, 0.5f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(-0.5f, 0.5f, 0.5f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(-0.5f, 0.5f, -0.5f);
            gl.glEnd();
            gl.glPopMatrix();
        // gl.glFlush();

        }

    }

    /**
     * Renderiza objeto do tipo Cilindro
     * @param Geometry
     * @param ListaGeometrias
     */
    void drawCylinder(Geometria g, ListaGeometrias listG) {

        if (triangularizada) {
            drawTriangularizada(g, listG);
        } else {
            if (g.isVisible() && listG.isVisible()) {
                if (!statusSelecao) {
                    gl.glPushMatrix();
                }
                if (listG.getVisibilidade() * 100 < 100.0f) {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            listG.getVisibilidade());
                } else {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            g.getVisibilidade());

                }
                float[] referenceLocal = g.getAtributos().getReferencial();
                gl.glTranslatef(referenceLocal[0], referenceLocal[1], referenceLocal[2]);
                gl.glNormal3f(0f, 0f, 1f);
                gl.glRotatef(g.getRotX(), 1.0f, 0.0f, 0.0f);
                gl.glRotatef(g.getRotY(), 0.0f, 1.0f, 0.0f);
                gl.glRotatef(g.getRotZ(), 0.0f, 0.0f, 1.0f);

                if (g.isSolid() && listG.isSolid()) {
                    glut.glutSolidCylinder(g.getAtributos().getRaio(), g.getAtributos().getAltura(), 15, 15);
                } else {
                    glut.glutWireCylinder(g.getAtributos().getRaio(), g.getAtributos().getAltura(), 15, 15);
                }
                if (!statusSelecao) {
                    gl.glPopMatrix();
                    gl.glFlush();
                }

            }
        }

    }

    /**
     * Renderiza objeto do tipo Esfera
     * @param Geometry
     * @param ListaGeometrias
     */
    void drawSphere(Geometria g, ListaGeometrias listG) {

        if (triangularizada) {
            drawTriangularizada(g, listG);
        } else {
            if (g.isVisible() && listG.isVisible()) {

                gl.glPushMatrix();
                if (listG.getVisibilidade() * 100 < 100.0f) {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            listG.getVisibilidade());
                } else {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            g.getVisibilidade());

                }

                gl.glPopMatrix();
                gl.glPushMatrix();
                float[] referenceLocal = g.getAtributos().getReferencial();
                gl.glTranslatef(referenceLocal[0], referenceLocal[1], referenceLocal[2]);
                gl.glNormal3f(0f, 0f, 1f);
                gl.glRotatef(g.getRotX(), 1.0f, 0.0f, 0.0f);
                gl.glRotatef(g.getRotY(), 0.0f, 1.0f, 0.0f);
                gl.glRotatef(g.getRotZ(), 0.0f, 0.0f, 1.0f);
                if (g.isSolid() && listG.isSolid()) {
                    glut.glutSolidSphere(g.getAtributos().getRaio(), 20, 20);
                } else {
                    glut.glutWireSphere(g.getAtributos().getRaio(), 20, 20);
                }
                gl.glPopMatrix();
                gl.glFlush();

            }
        }

    }

    /**
     * Renderiza objeto do tipo Cone
     * @param Geometry
     * @param ListaGeometrias
     */
    private void drawCone(Geometria g, ListaGeometrias listG) {

        if (triangularizada) {
            drawTriangularizada(g, listG);
        } else {

            if (g.isVisible() && listG.isVisible()) {
                gl.glPushMatrix();
                if (listG.getVisibilidade() * 100 < 100.0f) {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            listG.getVisibilidade());
                } else {
                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            g.getVisibilidade());

                }

                float[] referenceLocal = g.getAtributos().getReferencial();
                gl.glTranslatef(referenceLocal[0], referenceLocal[1], referenceLocal[2]);
                gl.glNormal3f(0f, 0f, 1f);
                gl.glRotatef(g.getRotX(), 1.0f, 0.0f, 0.0f);
                gl.glRotatef(g.getRotY(), 0.0f, 1.0f, 0.0f);
                gl.glRotatef(g.getRotZ(), 0.0f, 0.0f, 1.0f);

                if (g.isSolid() && listG.isSolid()) {
                    glut.glutSolidCone(g.getAtributos().getRaio(), g.getAtributos().getAltura(), 15, 15);
                } else {
                    glut.glutWireCone(g.getAtributos().getRaio(), g.getAtributos().getAltura(), 15, 15);
                }
                gl.glPopMatrix();
                gl.glFlush();

            }
        }
    }

    /**
     * Renderiza objeto do tipo Brick
     * @param Geometry
     * @param ListaGeometrias
     */
    private void drawBrick(Geometria g, ListaGeometrias listG) {

        if (triangularizada) {
            drawTriangularizada(g, listG);
        } else {
            if (g.isVisible() && listG.isVisible()) {

                gl.glPushMatrix();

                if (listG.getVisibilidade() * 100 < 100.0f) {

                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            listG.getVisibilidade());

                } else {

                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                    gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                            (float) g.getMaterial().getCor().getGreen() / 255,
                            (float) g.getMaterial().getCor().getBlue() / 255,
                            g.getVisibilidade());
                }

                float[] secondPoint = g.getAtributos().getSecondPoint();
                float[] firstPoint = g.getAtributos().getFirsPoint();

//                if (g.isSolid() && listG.isSolid()) {
//                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FLAT);
//                } else {
//                    gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE);
//                }
                gl.glRotatef(g.getRotX(), 1.0f, 0.0f, 0.0f);
                gl.glRotatef(g.getRotY(), 0.0f, 1.0f, 0.0f);
                gl.glRotatef(g.getRotZ(), 0.0f, 0.0f, 1.0f);

                desenhaTijolo3D(firstPoint, secondPoint);

                gl.glPopMatrix();
                gl.glFlush();

            }
        }

    }

    /**
     * @param g
     * @param listG
     */
    private void drawSTL(Geometria g, ListaGeometrias listG) {

        if (g.isVisible() && listG.isVisible()) {

            gl.glPushMatrix();
            Triangulo[] t;
            t = g.getListaTriangulos();
            Vertice[] v;
//            if (g.isSolid() && listG.isSolid()) {
//
//                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FLAT);
//
//            } else {
//                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE);
//            }
            gl.glNormal3f(0f, 0f, 1f);
            gl.glBegin(GL.GL_TRIANGLES);
            if (listG.getVisibilidade() * 100 < 100.0f) {
                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                        (float) g.getMaterial().getCor().getGreen() / 255,
                        (float) g.getMaterial().getCor().getBlue() / 255,
                        listG.getVisibilidade());
            } else {
                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
                gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                        (float) g.getMaterial().getCor().getGreen() / 255,
                        (float) g.getMaterial().getCor().getBlue() / 255,
                        g.getVisibilidade());

            }

            for (int i = 0; i < t.length; i++) {
                v = (Vertice[]) t[i].getVertice();
                for (int j = 0; j < 3; j++) {

                    gl.glVertex3f(v[j].getCoordenada(0), v[j].getCoordenada(1), v[j].getCoordenada(2));
                }
            }
            gl.glEnd();
            gl.glPopMatrix();
            // gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FLAT);
            gl.glFlush();

        }

    }

    /**
     * Método que desenha as Geometrias a partir da lista de triângulos. Neste caso
     * funciona apenas quando é feita a triangularização (quando é gerada a Malha para
     * FDTD 3D)
     * @param g
     * @param listG
     */
    private void drawTriangularizada(Geometria g, ListaGeometrias listG) {

        if (g.isVisible() && listG.isVisible()) {
            gl.glPushMatrix();
            Triangulo[] t = g.getListaTriangulos();

            Vertice[] v;
////            if (g.isSolid() && listG.isSolid()) {
////                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FLAT);
////            } else {
////                gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE);
////
////            }
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_SMOOTH);
            gl.glBegin(GL.GL_TRIANGLES);
            gl.glColor4f((float) g.getMaterial().getCor().getRed() / 255,
                    (float) g.getMaterial().getCor().getGreen() / 255,
                    (float) g.getMaterial().getCor().getBlue() / 255, g.getVisibilidade());

            for (int i = 0; i < t.length; i++) {
                v = (Vertice[]) t[i].getVertice();

                for (int j = 0; j < 3; j++) {
                    gl.glVertex3f(v[j].getCoordenada(0), v[j].getCoordenada(1), v[j].getCoordenada(2));
                }
            }
            gl.glEnd();
            gl.glPopMatrix();
//            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FLAT);
            gl.glFlush();

        }

    }

    /**
     * 
     * @param pI
     * @param pF
     */
    public void desenhaTijolo3D(float[] pI, float[] pF) {

        /* Face Frontal */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pI[0], pI[1], pI[2]);
        gl.glVertex3f(pF[0], pI[1], pI[2]);
        gl.glVertex3f(pF[0], pF[1], pI[2]);
        gl.glVertex3f(pI[0], pF[1], pI[2]);
        gl.glEnd();

        /* Face Esquerda */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pI[0], pI[1], pI[2]);
        gl.glVertex3f(pI[0], pI[1], pF[2]);
        gl.glVertex3f(pI[0], pF[1], pF[2]);
        gl.glVertex3f(pI[0], pF[1], pI[2]);
        gl.glEnd();

        /* Face Direita */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pF[0], pI[1], pI[2]);
        gl.glVertex3f(pF[0], pI[1], pF[2]);
        gl.glVertex3f(pF[0], pF[1], pF[2]);
        gl.glVertex3f(pF[0], pF[1], pI[2]);
        gl.glEnd();

        /* Face Cima */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pI[0], pF[1], pI[2]);
        gl.glVertex3f(pF[0], pF[1], pI[2]);
        gl.glVertex3f(pF[0], pF[1], pF[2]);
        gl.glVertex3f(pI[0], pF[1], pF[2]);
        gl.glEnd();

        /* Face Baixo */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pI[0], pF[1], pI[2]);
        gl.glVertex3f(pF[0], pF[1], pI[2]);
        gl.glVertex3f(pF[0], pF[1], pF[2]);
        gl.glVertex3f(pI[0], pF[1], pF[2]);
        gl.glEnd();

        /* Face Trazeira */
        gl.glBegin(gl.GL_QUADS);
        gl.glNormal3f(0f, 0f, 1f);
        gl.glVertex3f(pI[0], pI[1], pF[2]);
        gl.glVertex3f(pF[0], pI[1], pF[2]);
        gl.glVertex3f(pF[0], pF[1], pF[2]);
        gl.glVertex3f(pI[0], pF[1], pF[2]);
        gl.glEnd();



    }

    /*
     * prints out the contents of the selection array.
     */
    private void processHits(int hits, int buffer[]) {

        int names, ptr = 0;

        System.out.println("hits = " + hits);
        System.out.println("buffer size: " + buffer.length);
        // ptr = (GLuint *) buffer;
        for (int i = 0; i < hits; i++) { /* for each hit */
            names = buffer[ptr];
            System.out.println(" number of names for hit = " + names);
            ptr++;
            System.out.println("  z1 is " + buffer[ptr]);
            ptr++;
            System.out.println(" z2 is " + buffer[ptr]);
            ptr++;
            System.out.print("\n   the name is ");
            for (int j = 0; j < names; j++) { /* for each name */
                System.out.println("" + buffer[ptr]);
                objSelecionado = buffer[ptr];
                notificaObjSelecionado();
                ptr++;
            }
            System.out.println();
        }
    }

    /* Called by drawable to initiate drawing. */
    @Override
    public void display(GLAutoDrawable gLDrawable) {

        gl = gLDrawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();

        gl.glTranslatef(xPosition, yPosition, zPosition);

        gl.glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(rotateZ, 0.0f, 0.0f, 1.0f);

        if (statusCalculaCoordenada) {
            if (focus == 1) {
                //piso (ou seja, sobre a grade)
                gl.glBegin(GL.GL_QUADS);
                gl.glVertex3f(-tamGradeX * 2, -tamGradeY * 2, 0);
                gl.glVertex3f(tamGradeX * 2, -tamGradeY * 2, 0);
                gl.glVertex3f(tamGradeX * 2, tamGradeY * 2, 0);
                gl.glVertex3f(-tamGradeX * 2, tamGradeY * 2, 0);
                gl.glEnd();
            } else if (focus == 2) {
                //traseiras com Y na coordenada 0
                gl.glBegin(GL.GL_QUADS);
                gl.glVertex3f(-tamGradeX * 2, 0, tamGradeZ * 2);
                gl.glVertex3f(tamGradeX * 2, 0, tamGradeZ * 2);
                gl.glVertex3f(tamGradeX * 2, 0, -tamGradeZ * 2);
                gl.glVertex3f(-tamGradeX * 2, 0, -tamGradeZ * 2);
                gl.glEnd();
            } else if (focus == 0) {
                //meio com X na coordenada 0
                gl.glBegin(GL.GL_QUADS);
                gl.glVertex3f(0, tamGradeY * 2, tamGradeZ * 2);
                gl.glVertex3f(0, -tamGradeY * 2, tamGradeZ * 2);
                gl.glVertex3f(0, -tamGradeY * 2, -tamGradeZ * 2);
                gl.glVertex3f(0, tamGradeY * 2, -tamGradeZ * 2);
                gl.glEnd();
            } else if (focus == 3) {
                //piso (ou seja, sobre a grade)
                gl.glBegin(GL.GL_QUADS);
                gl.glVertex3f(-tamGradeX / 2, -tamGradeY / 2, 0);
                gl.glVertex3f(tamGradeX / 2, -tamGradeY / 2, 0);
                gl.glVertex3f(tamGradeX / 2, tamGradeY / 2, 0);
                gl.glVertex3f(-tamGradeX / 2, tamGradeY / 2, 0);
                gl.glEnd();
            }

            //Obtém as matrizes
            gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
            gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, mvmatrix, 0);
            gl.glGetDoublev(GL.GL_PROJECTION_MATRIX, projmatrix, 0);

            //Obtém a posição de X e Y do mouse
            int winX = xPos;
            int winY = yPos;

            //Obtém a posição de Z
            double winZ = 0;
            FloatBuffer z = FloatBuffer.allocate(1);
            z.clear();
            gl.glReadPixels(winX, winY, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, z);
            z.rewind();
            winZ = z.get();

            if (winZ != 1) {
                glu.gluUnProject(winX, winY, winZ, mvmatrix, 0, projmatrix, 0, viewport, 0, wcoord, 0);
                wcoord[3] = 0;
            } else {
                wcoord[0] = 0;
                wcoord[1] = 0;
                wcoord[2] = 0;
                wcoord[3] = -1;
            }

            statusCalculaCoordenada = false;
            glCanvas.display();
        } else {
            if (grid){
                drawGrid(gLDrawable);
            }
            if (eixos){
                drawEixos(gLDrawable);
            }

            if (clickEsfera == 2) {
                //Cria Esferas durante o desenho (visualizacao)
                gl.glPushMatrix();
                gl.glColor3d(0.0f, 0.4f, 0.8f);
                gl.glNormal3f(0f, 0f, 1f);
                gl.glTranslatef(this.xi, this.yi, this.zi);
                //gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
                glut.glutSolidSphere(this.raio, 20, 20);
                gl.glPopMatrix();
                gl.glFlush();
            }

            if (clickTijolo == 2) //evento durante o desenho (visualizacao)
            {

                float[] pI = new float[3];
                float[] pF = new float[3];
                pI[0] = this.xi;
                pI[1] = this.yi;
                pI[2] = this.zi;
                pF[0] = this.xf;
                pF[1] = this.yf;
                pF[2] = this.zf;
                gl.glPushMatrix();
                gl.glColor3d(0.0f, 0.4f, 0.8f);
                gl.glNormal3f(0f, 0f, 1f);
                desenhaTijolo3D(pI, pF);
                gl.glPopMatrix();
                gl.glFlush();


            }
            /* Desenha o tijolo com a profundidade */
            if (clickTijolo == 4) {

                float[] pI = new float[3];
                float[] pF = new float[3];
                pI[0] = this.xi;
                pI[1] = this.yi;
                pI[2] = this.zi;
                pF[0] = this.xf;
                pF[1] = this.yf;
                pF[2] = this.zf;
                //gl.glTranslatef(this.xi, this.yi, this.zi);
                gl.glPushMatrix();
                gl.glColor3d(0.0f, 0.4f, 0.8f);
                gl.glNormal3f(0f, 0f, 1f);
                desenhaTijolo3D(pI, pF);
                gl.glPopMatrix();
                gl.glFlush();

            }
            if (clickCilindro == 2) { //evento durante o desenho (visualizacao)

                gl.glPushMatrix();
                gl.glColor3d(0.0f, 0.4f, 0.8f);
                gl.glTranslatef(this.xi, this.yi, this.zi);
                gl.glNormal3f(1f, 1f, 1f);
                glut.glutSolidCylinder(this.raio, this.altura, 15, 15);
                gl.glPopMatrix();
                gl.glFlush();
            }

            if (clickCone == 2) {

                gl.glPushMatrix();
                gl.glColor3d(0.0f, 0.4f, 0.8f);
                gl.glTranslatef(this.xi, this.yi, this.zi);
                gl.glNormal3f(0f, 0f, 1f);
                glut.glutSolidCone(this.raio, this.altura, 15, 15);
                gl.glPopMatrix();
                gl.glFlush();
            }

             if (eixos){
                drawEixos(gLDrawable);
            }


            if (iListGeometryEmpty() == false) {
                renderTreeGeometrias();
            }

            if (iListFonteEmpty() == false) {
                renderTreeFontes();
            }

        }
    }

    public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged) {
    }

    public void init(GLAutoDrawable gLDrawable) {

        // Obtem referência ao GL
        gl = gLDrawable.getGL();
        // Especifica Cor de Fundo
        gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        // Pinta o Fundo da Tela com a Cor Escolhida
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Habilita a definição da cor do material a partir da cor corrente
        gl.glEnable(GL.GL_COLOR_MATERIAL);
        // Habilita o depth-buffer
        gl.glEnable(GL.GL_DEPTH_TEST);
        // Habilita o modelo de colorização de Gouraud
        gl.glShadeModel(gl.GL_SMOOTH);
        // Transparência
        gl.glEnable(gl.GL_BLEND);
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);
        // Estabelece os parâmetros do modelo de iluminação ambiente
        gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, luzAmbiente, 0);
        //Habilita uso de iluminação
        gl.glEnable(GL.GL_LIGHTING);
        // Habilita luz de número 0
        gl.glEnable(GL.GL_LIGHT0);

        gLDrawable.addKeyListener(this);
        gLDrawable.addMouseListener(this);
        gLDrawable.addMouseMotionListener(this);
        gLDrawable.addMouseWheelListener(this);

        gl.glDepthFunc(GL.GL_LEQUAL);								// The Type Of Depth Testing To Do
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);	// Really Nice Perspective Calculations
        gl.glEnable(GL.GL_TEXTURE_2D);
        texture = genTexture();
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture);
        TextureReader.Texture texture = null;
        try {
            texture = TextureReader.readTexture("Icones\\fonte.jpg");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        makeRGBTexture(texture, GL.GL_TEXTURE_2D, false);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
    }

    private void makeRGBTexture(Texture img, int target, boolean mipmapped) {

        if (mipmapped) {

            glu.gluBuild2DMipmaps(target, GL.GL_RGB8, img.getWidth(),
                    img.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
        } else {

            gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(),
                    img.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
        }
    }

    private int genTexture() {
        final int[] tmp = new int[1];
        gl.glGenTextures(1, tmp, 0);
        return tmp[0];
    }

    @Override
    public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height) {

        gl = gLDrawable.getGL();
        if (height <= 0) {
            height = 1;
        }

        h = (float) width / (float) height;
        gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 1.0, 2000.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    @Override
    public void keyPressed(KeyEvent e) {

     switch (e.getKeyChar()) {
            case 'x':
                addRotateX();
                break;
            case 'X':
                subRotateX();
                break;
            case 'y':
                addRotateY();
                break;
            case 'Y':
                subRotateY();
                break;
            case 'z':
                addRotateZ();
                break;
            case 'Z':
                subRotateZ();
                break;
            case '+':
                addZPosition();
                break;
            case '-':
                subZPosition();
                break;
            case 'w':
                addYPosition();
                break;
            case 's':
                subYPosition();
                break;
            case 'd':
                addXPosition();
                break;
            case 'a':
                subXPosition();
                break;
            case 'W':
                addYPosition();
                break;
            case 'S':
                subYPosition();
                break;
            case 'D':
                addXPosition();
                break;
            case 'A':
                subXPosition();
                break;
            case 'g':
                setDesenharGrid(!isGridEnable());
                break;
            case 'G':
                setDesenharGrid(!isGridEnable());
                break;
            case 'e':
                setDesenharEixos(!isEixosEnable());
                break;
            case 'E':
                setDesenharEixos(!isEixosEnable());
                break;
            case 'r':
                setVisao(rotateXInicial, rotateYInicial, rotateZInicial, xPositionInicial, yPositionInicial, zPositionInicial);
                glCanvas.display();
                break;
            case 'R':
                setVisao(rotateXInicial, rotateYInicial, rotateZInicial, xPositionInicial, yPositionInicial, zPositionInicial);
                glCanvas.display();
                break;
            case 32:
                teclado = true;
                clickMouse = 0;
                //System.out.println("teclado");
                /* Forca o redesenho */
                canvasFocus();
                break;
            case KeyEvent.VK_ENTER:
                teclado = false;
                clickMouse = 0;
                //System.out.println("teclado");
                /* Forca o redesenho */
                canvasFocus();
                break;
        }
    }

    public void keyReleased(KeyEvent e) {
    }

    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        clickMouse = 1;
        canvasFocus();
        // statusSelecao = true;
        //  statusCalculaCoordenada = true;

        glCanvas.display();

    }

    public void calculaCoordenada(int xPos, int yPos) {
        statusCalculaCoordenada = true;
        //statusSelecao = true;
        this.xPos = xPos;
        this.yPos = viewport[3] - yPos;
        glCanvas.display();
    }

    //evento de arrastar mouse
    @Override
    public void mouseDragged(MouseEvent e) {


        if (isConfirmar() == true) {

            calculaCoordenada(e.getX(), e.getY());

            //desenha esfera
            if (clickEsfera == 1) {
                //definindo o ponto inicial (x,y,z)
                this.xi = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yi = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zi = Util.decimalFormat(wcoord[2], 2).floatValue();
                clickEsfera = 2;
            }
            if (clickEsfera == 2) {
                //definindo o ponto final (x,y,z)
                this.xf = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yf = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zf = Util.decimalFormat(wcoord[2], 2).floatValue();

                //definindo o raio
                if (focus == 1 || focus == 3) {
                    double raioX = Math.abs(this.xf - this.xi);
                    double raioY = Math.abs(this.yf - this.yi);
                    this.raio = Util.decimalFormat((raioX > raioY ? raioX : raioY), 2).floatValue();
                } else if (focus == 2) {
                    double raioX = Math.abs(this.xf - this.xi);
                    double raioZ = Math.abs(this.zf - this.zi);
                    this.raio = Util.decimalFormat((raioX > raioZ ? raioX : raioZ), 2).floatValue();
                } else if (focus == 0) {
                    double raioY = Math.abs(this.yf - this.yi);
                    double raioZ = Math.abs(this.zf - this.zi);
                    this.raio = Util.decimalFormat((raioY > raioZ ? raioY : raioZ), 2).floatValue();
                }
                glCanvas.display();
            }

            //desenha cilindro
            if (clickCilindro == 1) {
                //definindo o ponto inicial (x,y,z)
                this.xi = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yi = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zi = Util.decimalFormat(wcoord[2], 2).floatValue();
                clickCilindro = 2;
            }
            if (clickCilindro == 2) {
                //definindo o ponto final (x,y,z)
                this.xf = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yf = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zf = Util.decimalFormat(wcoord[2], 2).floatValue();

                //definindo o raio e a altura
                if (focus == 1 || focus == 3) {
                    this.raio = Util.decimalFormat(Math.abs(this.xf - this.xi), 2);
                    this.altura = Util.decimalFormat(this.yf - this.yi, 2);
                } else if (focus == 2) {
                    this.raio = Util.decimalFormat(Math.abs(this.xf - this.xi), 2);
                    this.altura = Util.decimalFormat(this.zf - this.zi, 2);
                } else if (focus == 0) {
                    this.raio = Util.decimalFormat(Math.abs(this.yf - this.yi), 2);
                    this.altura = Util.decimalFormat(this.zf - this.zi, 2);
                }
                glCanvas.display();
            }

            //desenha cone
            if (clickCone == 1) {
                //definindo o ponto inicial (x,y,z)
                this.xi = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yi = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zi = Util.decimalFormat(wcoord[2], 2).floatValue();
                clickCone = 2;
            }
            if (clickCone == 2) {
                //definindo o ponto final (x,y,z)
                this.xf = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yf = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zf = Util.decimalFormat(wcoord[2], 2).floatValue();

                //definindo o raio e a altura
                if (focus == 1 || focus == 3) {
                    this.raio = Util.decimalFormat(Math.abs(this.xf - this.xi), 2);
                    this.altura = Util.decimalFormat(this.yf - this.yi, 2);
                } else if (focus == 2) {
                    this.raio = Util.decimalFormat(Math.abs(this.xf - this.xi), 2);
                    this.altura = Util.decimalFormat(this.zf - this.zi, 2);
                } else if (focus == 0) {
                    this.raio = Util.decimalFormat(Math.abs(this.yf - this.yi), 2);
                    this.altura = Util.decimalFormat(this.zf - this.zi, 2);
                }
                glCanvas.display();
            }

            //desenha tijolo
            if (clickTijolo == 1) {
                //definindo o ponto inicial (x,y,z)
                this.xi = Util.decimalFormat(wcoord[0], 2).floatValue();
                this.yi = Util.decimalFormat(wcoord[1], 2).floatValue();
                this.zi = Util.decimalFormat(wcoord[2], 2).floatValue();
                clickTijolo = 2;
            }
            if (clickTijolo == 2) {
                //definindo a largura e altura
                if (focus == 1 || focus == 3) {
                    this.xf = Util.decimalFormat(wcoord[0], 2).floatValue();
                    this.yf = Util.decimalFormat(wcoord[1], 2).floatValue();
                    this.zf = 0.0f;
                } else if (focus == 2) {
                    this.xf = Util.decimalFormat(wcoord[0], 2).floatValue();
                    this.yf = 0.0f;
                    this.zf = Util.decimalFormat(wcoord[2], 2).floatValue();
                } else if (focus == 0) {
                    this.xf = 0.0f;
                    this.yf = Util.decimalFormat(wcoord[1], 2).floatValue();
                    this.zf = Util.decimalFormat(wcoord[2], 2).floatValue();
                }
                glCanvas.display();
            }
            if (clickTijolo == 3 || clickTijolo == 4) {
                //definindo a profundidade
                if (focus == 1 || focus == 3) {
                    this.zf = Util.decimalFormat(wcoord[1] - this.yf, 2).floatValue();
                } else if (focus == 2) {
                    this.yf = Util.decimalFormat(-wcoord[2] + this.zf, 2).floatValue();
                } else if (focus == 0) {
                    this.xf = Util.decimalFormat(-wcoord[1] + this.yf, 2).floatValue();
                }
                glCanvas.display();
                clickTijolo = 4;
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {


        float[] firstPointt = new float[3];
        float[] secondPointt = new float[3];
        float[] referencet = new float[3];

        if (clickFonte == 1) {

            coordenadasFonte[0] = -((viewport[2] / 2) - (e.getX())) / blocoX;
            coordenadasFonte[1] = ((viewport[3] / 2) - (e.getY())) / blocoY;
            coordenadasFonte[2] = 0.0f;

            clickFonte = 0;
            clickEsfera = 0;
            clickTijolo = 0;
            clickCilindro = 0;
            clickCone = 0;
            clickLine = 0;
            glCanvas.display();
            setConfirmar(false);
            /* avisando que fonte foi criada */
            novaFonte();

        }

        if (clickEsfera == 2) {
            float[] reference = new float[3];

            reference[0] = this.xi;
            reference[1] = this.yi;
            reference[2] = this.zi;
            idGeo++;
            /* cria Objeto Geometry Esfera que sera retornado */

            Material materialDefault = new Material(true);
            materialDefault.setCor(new Color(0, 102, 204));
            geo = new Geometria(idGeo, "Esfera", new Esfera(this.raio, reference, idGeo), true, true, materialDefault, 0.0f, 0.0f, 0.0f);
            float[] ref = geo.getAtributos().getReferencial();
            geo.setListaTriangulos(geo.getAtributos().triangularizarGeometria());
            clickFonte = 0;
            clickEsfera = 0;
            clickTijolo = 0;
            clickCilindro = 0;
            clickCone = 0;
            clickLine = 0;
            glCanvas.display();
            setConfirmar(false);
            /* avisando que geometria foi criada */
            novaGeometria();

        }

        if (clickCilindro == 2) {
            float[] reference = new float[3];
            reference[0] = this.xi;
            reference[1] = this.yi;
            reference[2] = this.zi;
            idGeo++;
            /* cria Objeto Geometry Esfera que sera retornado */
            Material materialDefault = new Material(true);
            materialDefault.setCor(new Color(0, 102, 204));
            geo = new Geometria(idGeo, "Cilindro", new Cilindro(this.raio, this.altura, reference, idGeo), true, true, materialDefault, 0.0f, 0.0f, 0.0f);
            geo.setListaTriangulos(geo.getAtributos().triangularizarGeometria());
            clickFonte = 0;
            clickEsfera = 0;
            clickTijolo = 0;
            clickCilindro = 0;
            clickCone = 0;
            clickLine = 0;
            glCanvas.display();
            setConfirmar(false);
            novaGeometria();

        }

        if (clickCone == 2) {
            float[] reference = new float[3];
            reference[0] = this.xi;
            reference[1] = this.yi;
            reference[2] = this.zi;
            idGeo++;
            /* cria Objeto Geometry Esfera que sera retornado */
            Material materialDefault = new Material(true);
            materialDefault.setCor(new Color(0, 102, 204));
            geo = new Geometria(idGeo, "Cone", new Cone(this.raio, this.altura, reference, idGeo), true, true, materialDefault, 0.0f, 0.0f, 0.0f);
            geo.setListaTriangulos(geo.getAtributos().triangularizarGeometria());
            clickFonte = 0;
            clickEsfera = 0;
            clickTijolo = 0;
            clickCilindro = 0;
            clickCone = 0;
            clickLine = 0;
            glCanvas.display();
            setConfirmar(false);
            novaGeometria();

        }
        /* Etapa 2: define a primeira face do tijolo quando o usuario 
         * solta o botao do mouse
         */
        if (clickTijolo == 2) {
            referencet[0] = this.xi;
            referencet[1] = this.yi;
            referencet[2] = this.zi;

            //chama Etapa 3 - quando o usuario vai definir a profundidade (ver evento mouse dragged)
            clickTijolo = 3;
        }

        //Etapa 4: confirma a profundidade definida pelo usuario e remove o face recem criada
        if (clickTijolo == 4) {
            idGeo++;
            Material materialDefault = new Material(true);
            materialDefault.setCor(new Color(0, 102, 204));
            firstPointt[0] = this.xi;
            firstPointt[1] = this.yi;
            firstPointt[2] = this.zi;
            secondPointt[0] = this.xf;
            secondPointt[1] = this.yf;
            secondPointt[2] = this.zf;
            geo = new Geometria(idGeo, "Tijolo", new Tijolo(firstPointt, secondPointt, referencet, idGeo), true, true, materialDefault, 0.0f, 0.0f, 0.0f);
            geo.setListaTriangulos(geo.getAtributos().triangularizarGeometria());
            clickFonte = 0;
            clickEsfera = 0;
            clickTijolo = 0;
            clickCilindro = 0;
            clickCone = 0;
            clickLine = 0;
            glCanvas.display();
            setConfirmar(false);
            novaGeometria();
        }



    }

    /**
     * 
     * @param e
     */
    public void mousePressed(MouseEvent e) {//        switch (e.getButton()) {
//            case MouseEvent.BUTTON3:
//
//                statusSelecao = true;
//                statusCalculaCoordenada = true;
//                System.out.println("aqui");
//                glCanvas.display();
//                break;
//
//
//
//        }
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseMoved(MouseEvent e) {
    }

    /**
     * 
     * @param e
     */
    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() == -1) {

            addZPosition();
            glCanvas.display();

        } else {
            subZPosition();
            glCanvas.display();
        }
    }

    public double[] getWcoord() {
        return wcoord;
    }
}



